package com.mindcraft.user.serivce.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mindcraft.base.model.MindCraftResult;
import com.mindcraft.base.utils.CommonConst;
import com.mindcraft.base.utils.RedisUtils;
import com.mindcraft.user.mapper.McUserMapper;
import com.mindcraft.user.po.McUser;
import com.mindcraft.user.serivce.QQAuthService;
import com.mindcraft.user.vo.QQUserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Mr.M
 * @version 1.0
 * @description 微信扫码认证
 * @date 2022/9/29 12:12
 */
@Slf4j
@Service("qq_authservice")
public class QQAuthServiceImpl extends ServiceImpl<McUserMapper, McUser> implements QQAuthService {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    private McUserMapper mcUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public MindCraftResult qqlogin() {
        qrsign();
        MindCraftResult qqcheckMessage = qqLoginCheck();
        return qqcheckMessage;
    }

    @Override
    public QQUserVO getloginInfo(String qqacount) {

        String userToken = "";

        McUser one = mcUserMapper.selectOne
                (new LambdaQueryWrapper<McUser>().eq(McUser::getQq, qqacount));

        QQUserVO qquserVO = new QQUserVO();

        if (redisTemplate.hasKey(CommonConst.USER_TOKEN + one.getId())) {
            userToken = (String) redisTemplate.opsForValue().get(CommonConst.USER_TOKEN + one.getId());
        }else{
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            userToken = CommonConst.USER_ACCESS_TOKEN + uuid;

            redisTemplate.opsForValue().set(userToken, one, CommonConst.TOKEN_EXPIRE, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(CommonConst.USER_TOKEN + one.getId(), userToken, CommonConst.TOKEN_EXPIRE,TimeUnit.SECONDS);
        }

        BeanUtils.copyProperties(one,qquserVO);
        qquserVO.setAccessToken(userToken);

        return qquserVO;
    }


    private MindCraftResult qqLoginCheck() {

        String qrsig = qrsign();
        String url = "https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken="
                + GetqrToekn(qrsig) + "&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-" + System.currentTimeMillis() / 1000
                + "&js_ver=23111510&js_type=1&login_sig=wq86AwJQI8EHy*64BTWWA2G85ljJlI8BQvGND1nHFN-mcXYlKbHL2yPVGoDiEXmR&pt_uistyle=40&aid=549000912&daid=5&";

        try {

            Thread.sleep(500); // 休眠500毫秒
            HttpClient client = HttpClientBuilder.create().build();
            HttpGet request = new HttpGet(url);
            request.setHeader("Cookie", "qrsig=" + qrsig);

            CloseableHttpResponse response = null;
            String responseText = "";
            String responseBody = null;
            try {
                response = (CloseableHttpResponse) client.execute(request);
                HttpEntity entity = response.getEntity();

                if (entity != null) {
                    try (InputStream inputStream = entity.getContent()) {
                        // 从输入流中读取内容
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                        StringBuilder stringBuilder = new StringBuilder();
                        String line;
                        while ((line = reader.readLine()) != null) {
                            stringBuilder.append(line);
                        }
                        responseBody = stringBuilder.toString();
                    } catch (IOException e) {
                        // 处理异常
                    }
                }
                System.out.println(responseBody);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            if (response.getStatusLine().getStatusCode() == 200) {
                responseText = responseBody;

                if (responseText.contains("二维码未失效")) {
                    System.out.println(LocalDateTime.now().toString() + " 二维码未失效");

                    return MindCraftResult.success("二维码未失效");
                } else if (responseText.contains("二维码认证中")) {
                    RedisUtils redisUtils = new RedisUtils(redisTemplate);
                    redisUtils.updateValueWithTime("qrsignRequestCount");
                    System.out.println(LocalDateTime.now().toString() + " 二维码认证中");
                    return MindCraftResult.success("二维码认证中");

                } else if (responseText.contains("二维码已失效")) {

                    System.out.println(LocalDateTime.now().toString() + " 二维码已失效");

                    qrsig = qrsign(); // 获取新的qrsig

                    return MindCraftResult.success("二维码已失效");
                } else {
                    //获取用户信息添加数据库
                    System.out.println(LocalDateTime.now().toString() + " 登录成功");
                    Map<String, String> qqInfo = getQQInfo(responseText);
                    String qqacount = qqInfo.get("qqacount");
                    String qqname = qqInfo.get("qqname");
                    String qqavartar = getqqAvartar(qqacount);
                    qqInfo.put("qqavartar", qqavartar);
                    LambdaQueryWrapper<McUser> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(McUser::getQq, qqacount).eq(McUser::getUsername,qqname).eq(McUser::getUserpic,qqavartar);
                    if (StringUtils.isEmpty(mcUserMapper.selectOne(wrapper))) {
                        McUser mcUser = new McUser();
                        mcUser.setUtype("101002");
                        mcUser.setUsername(qqname);
                        mcUser.setName(qqname);
                        mcUser.setNickname(qqname);
                        mcUser.setEmail(qqacount + "@qq.com");
                        mcUser.setQq(qqacount);
                        mcUser.setUserpic(qqavartar);

                        mcUserMapper.insert(mcUser);
                    }

                    return MindCraftResult.success(200, "登录成功", qqInfo);
//                    return "登录成功ψ" + qqacount +"ψ"+ qqname + "ψ" + qqavartar;
//                    return qqNumber;
                }
            } else {
                System.out.println(LocalDateTime.now().toString() + " 请求登录失败");
                return MindCraftResult.success("请求登录失败");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    private String getqqAvartar(String qqacount) {
        String url = "http://q.qlogo.cn/headimg_dl?dst_uin=" + qqacount + "&spec=640&img_type=jpg";
        try {
            URL imageUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) imageUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.connect();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                // 成功接收到响应
                try (InputStream inputStream = connection.getInputStream()) {
                    return imageUrl.toString();
                }
            } else {
                // 请求发生错误
                System.out.println("请求发生错误，状态码：" + connection.getResponseCode());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;

    }


    private String qrsign() {

        String url = "https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=3&d=72&v=4&t=0.4440979972998541&daid=5&pt_3rd_aid=0";
        String qrsig = "";
        int qrsignRequestCount = 0;
        RedisUtils redisUtils = new RedisUtils(redisTemplate);
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(url);
            HttpResponse response = client.execute(request);

            int statusCode = response.getStatusLine().getStatusCode();


            if (statusCode == 200) {

                for (org.apache.http.Header header : response.getHeaders("Set-Cookie")) {
                    String[] cookieParts = header.getValue().split(";");
                    for (String part : cookieParts) {
                        if (part.startsWith("qrsig=")) {
                            qrsig = part.substring(6);
                            break;
                        }
                    }
                }


                if (!redisTemplate.hasKey("qrsignRequestCount")) {
                    redisUtils.updateValueWithTime("qrsignRequestCount");
                }

                if ((int) redisTemplate.opsForValue().get("qrsignRequestCount") > 100) {
                    HttpEntity entity = response.getEntity();
                    byte[] content = EntityUtils.toByteArray(entity);
                    Path filePath = Paths.get("QQToolChest.png");
                    if (Files.exists(filePath)) {
                        Files.delete(filePath);
                    }
                    Files.write(filePath, content, StandardOpenOption.CREATE);

                    System.out.println(java.time.LocalTime.now().toString() + " 登录二维码获取成功");
                } else {
                    System.out.println(java.time.LocalTime.now().toString() + " 获取二维码失败");
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }


        if (redisTemplate.hasKey("qrsignRequestCount")) {
            qrsignRequestCount = (int) redisTemplate.opsForValue().get("qrsignRequestCount");
        } else {
            redisUtils.updateValueWithTime("qrsignRequestCount");
        }


        if (redisTemplate.hasKey("qrsig")) {
            log.info("redis中取到了qrsig");
        } else {
            redisTemplate.opsForValue().set("qrsig", qrsig, 120, TimeUnit.SECONDS);
            log.info("存入qrsign{}", qrsig);
        }


        if ((int) redisTemplate.opsForValue().get("qrsignRequestCount") > 200) {
            //200秒后重新刷新qrsig
            redisUtils.updateValueWithTime("qrsignRequestCount");
            redisTemplate.opsForValue().set("qrsig", qrsig, 120, TimeUnit.SECONDS);
            log.info("存入新的qrsig{}", qrsig);
            return qrsig;
        } else {
            //获取老qrsig
            qrsig = (String) redisTemplate.opsForValue().get("qrsig");
            log.info("获取老的qrsig{}", qrsig);
            return qrsig;

        }

    }


    private Map<String, String> getQQInfo(String responseText) {
        Map<String, String> map = new HashMap<>();
        Pattern pattern = Pattern.compile("uin=(\\d+)");
        Matcher matcher = pattern.matcher(responseText);
        if (matcher.find()) {
            String uin = matcher.group(1);
            map.put("qqacount", uin);

        }
        int start = responseText.indexOf("'登录成功！', '") + "'登录成功！', '".length();
        int end = responseText.indexOf("'", start);
        String qqname = responseText.substring(start, end);
        map.put("qqname", qqname);
        return map;
    }


    private static int GetqrToekn(String qrsig) {
        int n = qrsig.length();
        int i = 0;
        int e = 0;
        while (n > i) {
            e += (e << 5) + (int) qrsig.charAt(i);
            i += 1;
        }
        return 2147483647 & e;
    }

}